package de.projectgoodmorning.alarm.model.gateway;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import de.projectgoodmorning.alarm.GatewayConnection;
import de.projectgoodmorning.alarm.model.generic.Alarm;

/**
 * Der CombinedAlarm ist ein zusammengesetzter Alarm (erbt nicht von Alarm).
 * Dieser Alarm besitzt neben dem Status auch einen Namen. Ein Hauptalarm
 * definiert das Wecksignal bzw. eine Hauptzeit.
 * 
 * Des Weiteren wird eine Liste mit GatewayAlarms gespeichert. Die Zeiten der
 * GatewayAlarms beziehen sich auf die Hauptzeit.
 * 
 * @see GatewayAlarm
 */
public class CombinedAlarm implements Serializable {
	private static final long serialVersionUID = 1L;

	public int id;
	private int state;
	public String name;
	protected Alarm mainAlarm;
	protected List<GatewayAlarm> alarms;

	/**
	 * erstellet einen neuen CombinedAlarm.
	 * 
	 * @param mainAlarm		erwartet einen Hauptalarm (Wecksingal und dessen Zeitpunkt)
	 */
	public CombinedAlarm( Alarm mainAlarm ) {
		if( mainAlarm == null ) {
			throw new IllegalArgumentException( "mainAlarm can not null" );
		}
		
		this.mainAlarm = mainAlarm;
		alarms = new ArrayList<GatewayAlarm>();
		state = mainAlarm.state;
	}

	/**
	 * fuegt einen neuen GatewayAlarm zum CombinedAlarm hinzu.
	 * Dieser Alarm wird in Abhaenigkeit zum Hauptalarm ausgefuehrt.
	 * 
	 * @param seconds	erwartet die Anzahl der Sekunden zum Hauptalarm,
	 * 					(Minus-Wert bedeutet BEVOR der Hauptalarm ausgefuehrt wird) 
	 * @param type		erwartet einen gueltigen Kommand-Typ, z.B. GatewayCommand.BLUE
	 * 					
	 * @see GatewayConnection#BLUE
	 */
	public void addAlarm( int seconds, int color ) {
		alarms.add( new GatewayAlarm( seconds, color ) );
	}

	/**
	 * entfernt einen hinzugefuegten Alarm anhand des Indizes der Liste.
	 * @param index		erwartet den Index des Alarms
	 */
	public void removeAlarm( int index ) {
		alarms.remove( index );
	}
	
	/**
	 * entfernt einen hinzugefuegten Alarm.
	 * @param alarm		erwartet den Alarm
	 */
	public void removeAlarm( GatewayAlarm alarm ) {
		alarms.remove( alarm );
	}

	/**
	 * entfernt alle Alarme aus der Liste.
	 */
	public void removeAllAlarms() {
		alarms.clear();
	}
	
	/**
	 * gibt den Hauptalarm zurueck
	 */
	public Alarm getMainAlarm() {
		return mainAlarm;
	}
	
	/**
	 * ermittelt den Status des CombinedAlarms und gibt diesen zurueck.
	 * Die Ermittelung erfolgt ueber den Hauptalarm als auch ueber alle
	 * hinzugefuegten Alarme.
	 * Sollte nur ein Alarm aktiv sein, ist der CombinedAlarm ebenfalls aktiv.
	 * Nur wenn alle inaktiv sind, ist der CombinedAlarm inaktiv.
	 * 
	 * @return gibt den Status des Alarms zurueck
	 * @see		Alarm#ACTIVE
	 * @see		Alarm#INACTIVE
	 */
	public int getState() {
		state = mainAlarm.state;
		if( state == Alarm.ACTIVE ) {
			return state;
		} else {
			for( Alarm a : alarms ) {
				if( a.state == Alarm.ACTIVE ) {
					state = Alarm.ACTIVE;
					break;
				}
			}
		}
		
		return state;
	}

	/**
	 * gibt alle hinzugefuegten Alarme als Array zurueck
	 */
	public GatewayAlarm[] getGatewayAlarms() {
		GatewayAlarm[] arr = new GatewayAlarm[alarms.size()];
		alarms.toArray( arr );
		return arr;
	}

	/**
	 * erstellt fuer alle hinzugefuegten Alarme einen festen Zeitpunkt in 
	 * Abhaenigkeit zum Hauptalarm und gibt diese einschliesslich des 
	 * Hauptalarms zurueck.
	 * 
	 * @return
	 */
	public Alarm[] exportAll() {
		Calendar now = Calendar.getInstance();
		Calendar temp = Calendar.getInstance();
		temp.setTimeInMillis( mainAlarm.getMoment() );

		Calendar alarm = Calendar.getInstance();
		alarm.set( Calendar.HOUR_OF_DAY, temp.get( Calendar.HOUR_OF_DAY ) );
		alarm.set( Calendar.MINUTE, temp.get( Calendar.MINUTE ) );
		alarm.set( Calendar.SECOND, temp.get( Calendar.SECOND ) );

		if( alarm.before( now ) ) {
			alarm.add( Calendar.DAY_OF_MONTH, 1 );
		}

		mainAlarm.setMoment( alarm );

		Alarm[] arr = new Alarm[alarms.size() + 1];
		int i = 0;

		for( GatewayAlarm ga : alarms ) {
			alarm.setTimeInMillis( mainAlarm.getMoment() );
			alarm.add( Calendar.SECOND, ga.seconds );
			ga.setMoment( alarm.getTimeInMillis() );

			arr[i++] = ga;
		}

		arr[alarms.size()] = mainAlarm;
		return arr;
	}

	/**
	 * gibt einen vorhandenen Alarm anhand seiner ID zurueck
	 * @param id	erwartet die ID eines Alarms
	 * @return		gibt Instanz zurueck wenn vorhanden, sonst null
	 */
	public GatewayAlarm getByID( int id ) {
		for( GatewayAlarm ga : alarms ) {
			if( ga.id == id ) {
				return ga;
			}
		}
		return null;
	}
}